﻿
Public Module _serializer
    'convert a structure into bytes
    Public Function serialize(ByRef buff() As Byte,
                              ByVal start As Int64,
                              ByRef size As Int64,
                              ByVal take As _do(Of bytes, UInt64, Boolean)) As Boolean
        If take Is Nothing OrElse start > maxInt32 OrElse start < 0 Then
            Return False
        End If

        size = 0
        Dim i As UInt64 = 0
        Dim bt As bytes = Nothing
        While take(bt, i)
            i += 1
            If bt Is Nothing Then
                size += sizeofInt64
            Else
                size += bt.size + sizeofInt64
            End If
        End While

        If buff Is Nothing OrElse start = 0 Then
            ReDim buff(start + size - 1)
        ElseIf buff.Length() < start + size Then
            ReDim Preserve buff(start + size - 1)
        End If

        Dim p As Int32 = 0
        p = start
        i = 0
        While take(bt, i)
            i += 1
            Dim sz As Int64 = 0
            If bt Is Nothing Then
                sz = 0
            Else
                sz = bt.size()
            End If
            assert(convertor.tobytes(sz, buff, p))
            If Not bt Is Nothing Then
                memcpy(buff, p, +bt)
                p += sz
            End If
        End While
        assert(p = start + size)

        Return True
    End Function

    Public Function serialize(ByRef buff() As Byte,
                              ByVal start As Int64,
                              ByRef size As Int64,
                              ByVal ParamArray args() As bytes) As Boolean
        If args Is Nothing OrElse args.Length() = 0 Then
            Return False
        End If

        Return serialize(buff, start, size,
                         Function(ByRef b As bytes, ByRef i As UInt64) As Boolean
                             If i >= args.Length() Then
                                 Return False
                             Else
                                 b = args(i)
                                 Return True
                             End If
                         End Function)
    End Function

    Private Const defaultWithTypes As Boolean = True

    Public Function serialize(ByRef buff() As Byte,
                              ByVal start As Int64,
                              ByRef size As Int64,
                              ByVal withTypes As Boolean,
                              ByVal ParamArray args() As toBytes) As Boolean
        If args Is Nothing OrElse args.Length() = 0 Then
            Return False
        End If

        Dim bts() As bytes = Nothing
        If withTypes Then
            ReDim bts((args.Length() << 1) - 1)
            For i As Int64 = 0 To args.Length() - 1
                Dim t As String = Nothing
                If args(i) Is Nothing Then
                    t = types_cache.defaultTypeName
                    bts((i << 1) + 1) = Nothing
                Else
                    assert(types_cache.[get](args(i), t))
                    bts((i << 1) + 1) = args(i).tobytes()
                End If
                bts(i << 1) = (New bytesString(t)).tobytes()
            Next
        Else
            ReDim bts(args.Length() - 1)
            For i As Int64 = 0 To args.Length() - 1
                If args(i) Is Nothing Then
                    bts(i) = Nothing
                Else
                    bts(i) = args(i).tobytes()
                End If
            Next
        End If

        Return serialize(buff, start, size, bts)
    End Function

    Public Function serialize(ByRef buff() As Byte,
                              ByVal start As Int64,
                              ByRef size As Int64,
                              ByVal ParamArray args() As toBytes) As Boolean
        Return serialize(buff, start, size, defaultWithTypes, args)
    End Function

    Public Function serialize(ByRef output As bytes,
                              ByVal withTypes As Boolean,
                              ByVal ParamArray args() As toBytes) As Boolean
        Dim buff() As Byte = Nothing
        Dim size As Int64 = 0
        If serialize(buff, 0, size, withTypes, args) Then
            assert(buff.Length() = size)
            If output Is Nothing Then
                output = New bytes()
            End If
            output.attach(buff)
            Return True
        Else
            Return False
        End If
    End Function

    Public Function serialize(ByRef output As bytes, ByVal ParamArray args() As toBytes) As Boolean
        Return serialize(output, defaultWithTypes, args)
    End Function
End Module
